---
title: Lire un Provider
--- 

import Tabs from "@theme/Tabs";
import TabItem from "@theme/TabItem";
import CodeBlock from "@theme/CodeBlock";
import counter from "!!raw-loader!/i18n/fr/docusaurus-plugin-content-docs/current/concepts/reading_counter.dart";
import consumerWidget from "!!raw-loader!/i18n/fr/docusaurus-plugin-content-docs/current/concepts/reading_consumer_widget.dart";
import consumerStatefulWidget from "!!raw-loader!/i18n/fr/docusaurus-plugin-content-docs/current/concepts/reading_consumer_stateful_widget.dart";
import consumerHookWidget from "!!raw-loader!/i18n/fr/docusaurus-plugin-content-docs/current/concepts/reading_consumer_hook_widget.dart";
import consumerHook from "!!raw-loader!/i18n/fr/docusaurus-plugin-content-docs/current/concepts/reading_consumer_hook.dart";
import watch from "!!raw-loader!/i18n/fr/docusaurus-plugin-content-docs/current/concepts/reading_watch.dart";
import watchBuild from "!!raw-loader!/i18n/fr/docusaurus-plugin-content-docs/current/concepts/reading_watch_build.dart";
import listen from "!!raw-loader!/i18n/fr/docusaurus-plugin-content-docs/current/concepts/reading_listen.dart";
import listenBuild from "!!raw-loader!/i18n/fr/docusaurus-plugin-content-docs/current/concepts/reading_listen_build.dart";
import read from "!!raw-loader!/i18n/fr/docusaurus-plugin-content-docs/current/concepts/reading_read.dart";
import readBuild from "!!raw-loader!/i18n/fr/docusaurus-plugin-content-docs/current/concepts/reading_read_build.dart";
import readNotifierBuild from "!!raw-loader!/i18n/fr/docusaurus-plugin-content-docs/current/concepts/reading_read_notifier_build.dart";
import watchNotifierBuild from "!!raw-loader!/i18n/fr/docusaurus-plugin-content-docs/current/concepts/reading_watch_notifier_build.dart";
import { trimSnippet } from "../../../../../src/components/CodeSnippet";

Avant de lire ce guide, assurez-vous d'abord de [lire sur les Providers](/docs/concepts/providers).

Dans ce guide, nous verrons comment consommer un provider.

## Obtention d'un objet "ref"

Tout d'abord, avant de lire un provider, nous devons obtenir un objet "ref".

Cet objet nous permet d'interagir avec les providers, que ce soit à partir d'un widget
ou d'autres providers.

### Obtention d'un "ref" depuis a provider

Tous les providers reçoivent un "ref" comme paramètre :

```dart
final provider = Provider((ref) {
  // utiliser ref pour obtenir d'autres providers
  final repository = ref.watch(repositoryProvider);

  return SomeValue(repository);
})
```
Ce paramètre peut être passé à la valeur exposée par le provider sans danger.

Par exemple, un cas d'utilisation courant consiste à transmettre le "ref" du provider à un [StateNotifier]:

<CodeBlock>{trimSnippet(counter)}</CodeBlock>

Cela permettrait à notre classe `Counter` de lire les providers.

### Obtention d'un "ref" à partir d'un widget

Les widgets ne disposent naturellement pas d'un paramètre ref. Mais [Riverpod] propose plusieurs
solutions pour en obtenir un, à partir des widgets.

### Étendre de ConsumerWidget au lieu de StatelessWidget

La solution la plus courante consistera à remplacer [StatelessWidget] par [ConsumerWidget].
lors de la création d'un widget.

Le [ConsumerWidget] est fondamentalement identique au [StatelessWidget], 
avec la seule différence est qu'elle possède un paramètre supplémentaire 
dans sa méthode de construction : l'objet "ref".

Une [ConsumerWidget] classique ressemblerait à ceci :

<CodeBlock>{trimSnippet(consumerWidget)}</CodeBlock>

### Étendre ConsumerStatefulWidget+ConsumerState au lieu de StatefulWidget+State

Similaires à [ConsumerWidget], [ConsumerStatefulWidget] et [ConsumerState] 
sont l'équivalent d'une [StatefulWidget] avec son [State], à la différence que l'état (the state) est un objet "ref".

Cette fois, le "ref" n'est pas passé comme paramètre de la méthode build, 
mais est plutôt une propriété de l'objet [ConsumerState]:

<CodeBlock>{trimSnippet(consumerStatefulWidget)}</CodeBlock>

### Étendre HookConsumerWidget au lieu de HookWidget

Cette solution est spécifique aux utilisateurs de [flutter_hooks]. Étant donné que [flutter_hooks] 
nécessite d'étendre de [HookWidget] pour fonctionner. Les widgets qui utilisent les hooks sont incapables 
d'étendre [ConsumerWidget].

Une solution consiste, à travers le package [hooks_riverpod], 
à remplacer [HookWidget] par [HookConsumerWidget].

Un exemple serait:

<CodeBlock>{trimSnippet(consumerHookWidget)}</CodeBlock>

### Les widgets Consumer et HookConsumer

Une dernière solution pour obtenir un "ref" à l'intérieur des widgets est de se servir 
de [Consumer]/[HookConsumer].

Ces classes sont des widgets qui peuvent être utilisés pour obtenir un "ref", avec les mêmes propriétés 
que [ConsumerWidget]/[HookConsumerWidget]

Ces widgets peuvent être un moyen d'obtenir un "ref" sans avoir à définir une classe. 
Un exemple serait :

<CodeBlock>{trimSnippet(consumerHook)}</CodeBlock>

## Usage de ref pour interagir avec les providers

Maintenant que nous avons un "ref", on peut commencer à l'utiliser.

Il y a trois utilisations principales de "ref" :

- Obtenir la valeur d'un provider et écouter les changements, 
  de sorte que lorsque cette valeur change, cela reconstruira 
  le widget ou le provider qui s'est abonné à la valeur.
  Cela peut être fait en utilisant `ref.watch`.
- L'ajout d'un listener sur un provider, 
  pour exécuter une action à chaque fois que ce provider change.
  Cela peut être fait en utilisant `ref.listen`.
- Obtenir la valeur d'un provider tout en ignorant les changements.
  Cela est utile lorsque nous avons besoin de la valeur d'un provider 
  dans un événement tel que "on click".
  Cela peut être fait en utilisant `ref.read`.

:::note
Quand c'est possible, il est préférable d'utiliser `ref.watch` 
plutôt que `ref.read` ou `ref.listen` pour implémenter 
une fonctionnalité.  
En changeant votre implémentation pour qu'elle se base sur 
`ref.watch`, elle devient à la fois réactive et déclarative, 
ce qui rend votre application plus facile à maintenir.
:::

### Usage de ref.watch pour observer un provider

Il est possible d'utiliser `ref.watch` dans la méthode `build` d'un widget ou a l'interieur 
d'un provider pour que le widget/le provider écoute le provider.

Par exemple, un provider pourrait utiliser `ref.watch` pour combiner 
plusieurs providers en une nouvelle valeur.

Un exemple serait le filtrage d'une todo-list.
On pourrait avoir deux providers:

- `filterTypeProvider`, un provider qui expose (révèle) le type actuel du filtre
   (none, show only completed tasks, ...)
- `todosProvider`, un provider qui expose (révèle) la liste des tâches.

Grâce à cela, en utilisant `ref.watch`, on peut créer un troisième provider 
qui combine les deux autre providers pour créer une liste filtrée de tâches :

<CodeBlock>{trimSnippet(watch)}</CodeBlock>

Avec ce code, `filteredTodoListProvider` expose (révèle) maintenant la liste filtrée des tâches.

La liste filtrée sera également mise à jour automatiquement si 
le filtre ou la liste de tâches a changée. Mais en même temps, 
la liste filtrée ne sera pas recalculée si ni le filtre ni la liste
des tâches n'ont changé.

De la même manière, un widget pourrait utiliser `ref.watch` 
pour montrer une interface utilisateur qui dépend d'un provider:

<CodeBlock>{trimSnippet(watchBuild)}</CodeBlock>

Ce snippet montre un widget qui écoute un provider qui stocke 
un compteur. Et si ce compteur change, le widget sera reconstruit 
et l'interface utilisateur sera mise à jour pour montrer la nouvelle 
valeur.

:::caution
La méthode `watch` ne doit pas être appelée de manière asynchrone,
comme dans `onPressed` ou un [ElevatedButton]. Elle ne doit pas non plus être utilisée 
dans `initState` et d'autres cycles de vie de [State].

Dans ces cas, pensez à utiliser `ref.read` à la place.
:::

### Usage de ref.listen pour réagir au changements d'un provider

De la même manière que `ref.watch`, il est possible d'utiliser `ref.listen` 
pour observer un provider.

La principale différence entre eux est que, plutôt que de reconstruire 
le widget/provider si le provider écouté change, l'utilisation 
de `ref.listen` appellera plutôt une fonction personnalisée.

Cela peut être utile pour effectuer des actions lorsqu'un certain changement se produit, 
par exemple d'afficher un snackbar lorsqu'une erreur se produit.

La méthode `ref.listen` a besoin de 2 arguments positionnels, le premier est le Provider et 
le second est la fonction callback que nous voulons exécuter lorsque l'état (state) change.
La fonction callback, lorsqu'elle est appelée, renvoie deux valeurs, 
la valeur de l'état (state) précédent et la valeur du nouvel état (state).

La méthode `ref.listen` peut etre utilisée à l'intérieur d'un provider.

<CodeBlock>{trimSnippet(listen)}</CodeBlock>

Ou à l'intérieur de la méthode `build` d'un widget:

<CodeBlock>{trimSnippet(listenBuild)}</CodeBlock>

:::caution
La méthode `listen` ne doit pas être appelée de manière asynchrone,
comme dans `onPressed` ou un [ElevatedButton]. Elle ne doit pas non 
plus être utilisée dans `initState` et dans d'autres cycles 
de vie de [State].
:::

### Usage de ref.read pour obtenir l'état d'un provider qu'une fois

La méthode `ref.read` est un moyen d'obtenir l'état d'un provider, 
sans aucun effet supplémentaire.

Il est généralement utilisé dans les fonctions déclenchées par les interactions de l'utilisateur.
Par exemple, on peut utiliser `ref.read` pour incrémenter 
un compteur lorsqu'un utilisateur clique sur un bouton :

<CodeBlock>{trimSnippet(read)}</CodeBlock>

:::note
L'utilisation de `ref.read` doit être évitée autant que possible.

Il existe une solution pour contourner les cas où l'utilisation 
de `watch` ou `listen` serait trop peu pratique à utiliser. 
Si vous le pouvez, il est presque toujours préférable d'utiliser 
`watch`/`listen`, surtout `watch`.
:::

#### **NE PAS** utiliser `ref.read` à l'intérieur de la méthode build

Vous pouvez être tenté d'utiliser `ref.read` pour optimiser 
les performances d'un widget en faisant :

<CodeBlock>{trimSnippet(readBuild)}</CodeBlock>

Mais ce n'est pas une bonne pratique et cela peut provoquer des bogues difficiles à repérer.

L'utilisation de `ref.read` de cette manière est généralement associée à la idée "La valeur exposée par un provider ne change jamais, 
donc utiliser 'ref.read' est sûr".
Le problème avec cette supposition est que, si aujourd'hui ce provider 
peut en effet ne jamais mettre à jour sa valeur, rien ne 
garantit que ce sera le cas demain. la même chose.

Les softwares ont tendance à beaucoup changer, et il est probable qu'à l'avenir, une valeur qui n'a 
jamais changé devra être modifiée.

Mais si vous utilisiez `ref.read`, quand cette valeur commence 
à changer, vous allez devoir passer par toute votre codebase pour 
changer `ref.read` en `ref.watch` - ce qui est ce qui favorise 
les erreurs et il y a de fortes chances que vous en oubliiez certaines.

Alors que si vous utilisez `ref.watch` des le début, vous n'aurez aucun problème.

**_Mais je voulais utiliser `ref.read` pour réduire le nombre de fois où mon widget est reconstruit._**

Bien que l'objectif soit méritant, il est important de noter que vous pouvez atteindre exactement le même effet 
(réduire le nombre de constructions) en utilisant `ref.watch` à la place.

Les providers offrent différents moyens d'obtenir une valeur tout en réduisant le nombre de reconstructions, 
que vous pourriez utiliser à la place.

Par exemple, au lieu de 

<CodeBlock>{trimSnippet(readNotifierBuild)}</CodeBlock>

On peut faire

<CodeBlock>{trimSnippet(watchNotifierBuild)}</CodeBlock>

On obtient les mêmes effets dans les deux exemples: notre bouton ne se reconstruira 
pas lorsque le compteur s'incrémente.

En revanche, la deuxième approche prend en charge les cas où le compteur est remis à zéro. 
Par exemple, une autre partie de l'application pourrait appeler :

```dart
ref.refresh(counterProvider);
```

ce qui recrée l'objet `StateController`.

Si nous avions utilisé `ref.read` ici, notre bouton utiliserait toujours 
la précédente instance de `StateController` précédente, qui a été éliminée et 
ne doit plus être utilisée. Alors que l'utilisation de `ref.watch` reconstruit correctement le bouton pour utiliser le nouveau `StateController`.

## Décider ce qu'il faut lire

En fonction du provider que vous voulez écouter, vous pouvez 
avoir plusieurs valeurs possibles à écouter.

À titre d'exemple, considérons le [StreamProvider] suivant :

```dart
final userProvider = StreamProvider<User>(...);
```

En lisant ce `userProvider`, vous pouvez :

- lire de manière synchrone l'état actuel en écoutant le `userProvider` lui-même :

  ```dart
  Widget build(BuildContext context, WidgetRef ref) {
    AsyncValue<User> user = ref.watch(userProvider);

    return user.when(
      loading: () => const CircularProgressIndicator(),
      error: (error, stack) => const Text('Oops'),
      data: (user) => Text(user.name),
    );
  }
  ```
- obtenir le [Stream] associé, en écoutant `userProvider.stream` :
  
  ```dart
  Widget build(BuildContext context, WidgetRef ref) {
    Stream<User> user = ref.watch(userProvider.stream);
  }
  ```

- obtenir un [Future] qui sera la dernière valeur émise, en écoutant `userProvider.last` :
  
  ```dart
  Widget build(BuildContext context, WidgetRef ref) {
    Future<User> user = ref.watch(userProvider.future);
  }
  ```

D'autres providers peuvent offrir des valeurs alternatives différentes. 
Pour plus d'informations, reportez-vous à la documentation de chaque 
provider en consultant la [Référence API](https://pub.dev/documentation/riverpod/latest/riverpod/riverpod-library.html).

## Usage de "select" pour filtrer les 'rebuilds'

Une dernière fonctionnalité à mentionner concernant la lecture des providers est la possibilité 
de réduire le nombre de reconstructions d'un widget/provider, ou combien de fois `ref.listen` exécute une fonction.

Il est important de garder cela à l'esprit car, par défaut, 
l'écoute d'un provider porte sur l'objet entier. 
Mais dans certains cas, un widget/provider peut ne s'intéresser qu'à 
certaines propriétés au lieu de l'objet entier.

Par exemple, un provider peut exposer (révèle) un `User` :

```dart
abstract class User {
  String get name;
  int get age;
}
```

Mais un widget ne peut utiliser que le nom d'utilisateur :

```dart
Widget build(BuildContext context, WidgetRef ref) {
  User user = ref.watch(userProvider);
  return Text(user.name);
}
```

Si nous avions utilisé naïvement `ref.watch`, cela aurait reconstruit 
le widget lorsque l'âge de "User" change.

La solution est d'utiliser `select` pour dire explicitement à Riverpod que nous voulons seulement 
écouter que certaines propriétés de "User".

Le nouveau code sera: 

```dart
Widget build(BuildContext context, WidgetRef ref) {
  String name = ref.watch(userProvider.select((user) => user.name))
  return Text(name);
}
```

La façon dont cela fonctionne en utilisant `select` est la suivante : nous 
spécifions une fonction qui renvoie la propriété qui nous intéresse.

Ensuite, chaque fois que 'User' changera, 
Riverpod appellera cette fonction et comparera le résultat précédent 
et le nouveau. S'ils sont différents (par exemple lorsque le nom a changé), 
Riverpod reconstruira le widget. 
Mais s'ils sont égaux (comme lorsque l'âge a changé), 
Riverpod ne reconstruira pas le widget.

:::info
Il est aussi possible d'utiliser `select` avec `ref.listen`:

```dart
ref.listen<String>(
  userProvider.select((user) => user.name),
  (String? previousName, String newName) {
    print('The user name changed $newName');
  }
);
```


En faisant cela, le listener ne sera appelé que lorsque le nom changera.
:::

:::tip
Il n'est pas nécessaire de retourner une propriété de l'objet. 
Toute valeur qui
override == fonctionnera. Par exemple, vous pouvez faire :

```dart
final label = ref.watch(userProvider.select((user) => 'Mr ${user.name}'));
```
:::

[provider]: https://pub.dev/documentation/riverpod/latest/riverpod/Provider-class.html
[stateprovider]: https://pub.dev/documentation/riverpod/latest/riverpod/StateProvider-class.html
[providercontainer]: https://pub.dev/documentation/riverpod/latest/riverpod/ProviderContainer-class.html
[providerlistener]: https://pub.dev/documentation/flutter_riverpod/latest/flutter_riverpod/ProviderListener-class.html
[providerscope]: https://pub.dev/documentation/flutter_riverpod/latest/flutter_riverpod/ProviderScope-class.html
[consumer]: https://pub.dev/documentation/flutter_riverpod/latest/flutter_riverpod/Consumer-class.html
[consumerwidget]: https://pub.dev/documentation/flutter_riverpod/latest/flutter_riverpod/ConsumerWidget-class.html
[consumerstate]: https://pub.dev/documentation/flutter_riverpod/latest/flutter_riverpod/ConsumerStatefulWidget-class.html
[consumerstatefulwidget]: https://pub.dev/documentation/flutter_riverpod/latest/flutter_riverpod/ConsumerState-class.html
[useprovider]: https://pub.dev/documentation/hooks_riverpod/latest/hooks_riverpod/ref.watch(.html
[elevatedbutton]: https://api.flutter.dev/flutter/material/ElevatedButton-class.html
[streambuilder]: https://api.flutter.dev/flutter/widgets/StreamBuilder-class.html
[riverpod]: https://github.com/rrousselgit/riverpod
[text]: https://api.flutter.dev/flutter/widgets/Text-class.html
[hooks_riverpod]: https://pub.dev/packages/hooks_riverpod
[future]: https://api.dart.dev/stable/2.13.4/dart-async/Future-class.html
[stream]: https://api.dart.dev/stable/2.13.4/dart-async/Stream-class.html
[hookwidget]: https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/HookWidget-class.html
[hookconsumerwidget]: https://pub.dev/documentation/hooks_riverpod/latest/hooks_riverpod/HookConsumerWidget-class.html
[hookconsumer]: https://pub.dev/documentation/hooks_riverpod/latest/hooks_riverpod/HookConsumer-class.html
[flutter_riverpod]: https://pub.dev/packages/flutter_riverpod
[flutter_hooks]: https://github.com/rrousselGit/flutter_hooks
[statenotifierprovider]: https://pub.dev/documentation/riverpod/latest/riverpod/StateNotifierProvider-class.html
[statenotifier]: https://pub.dev/documentation/state_notifier/latest/state_notifier/StateNotifier-class.html
[streamprovider]: https://pub.dev/documentation/riverpod/latest/riverpod/StreamProvider-class.html
[statelesswidget]: https://api.flutter.dev/flutter/widgets/StatelessWidget-class.html
[statefulwidget]: https://api.flutter.dev/flutter/widgets/StatefulWidget-class.html
[state]: https://api.flutter.dev/flutter/widgets/State-class.html
